/*
 * Student Name: Philippe Gambling
 * Course: CSCI 5733
 * Assignment: Homework 1
 * Created: Jun 16, 2009
 * Modified: Jun 16, 2009
 * 
 * Class Name: CnetSource
 * Description: Retrieves and parses CNET RSS feeds.
 */

package csci5733.hw1;

import java.text.ParseException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Hashtable;
import java.util.Iterator;
import java.util.List;
import org.xml.sax.*;
import org.xml.sax.helpers.DefaultHandler;
import org.xml.sax.helpers.XMLReaderFactory;


/**
 *
 * @author Philippe Gambling
 */
public class CnetSource extends DefaultHandler implements NewsSource  {
    private NewsUrl url;
    private static Hashtable<String,ArrayList> supportedTopics = new Hashtable();

    private List newsItemList = new ArrayList();
    private NewsItem currentItem;
    private String currentText = "";
    private String source = "cnet";

    private boolean parsingItem = false;

    public CnetSource(NewsUrl u) {
        super();
        // Map my topics to CNET's topics
        CnetSource.supportedTopics.put("software",
                new ArrayList<String>(Arrays.asList("software")));
        CnetSource.supportedTopics.put("hardware",
                new ArrayList<String>(Arrays.asList("hardware")));
        CnetSource.supportedTopics.put("security",
                new ArrayList<String>(Arrays.asList("security")));
        CnetSource.supportedTopics.put("network",
                new ArrayList<String>(Arrays.asList("network")));
        CnetSource.supportedTopics.put("internet",
                new ArrayList<String>(Arrays.asList("internet")));
        CnetSource.supportedTopics.put("personal",
                new ArrayList<String>(Arrays.asList("personal")));
        CnetSource.supportedTopics.put("enterprise",
                new ArrayList<String>(Arrays.asList("software","hardware")));
        this.url = u;
    }

    @Override
    public List fetchTopic(String topic) throws Exception {
        // Return an empty list if this isn't a known CNET topic.
        if(!(CnetSource.supportedTopics.keySet().contains(topic))) {
            return new ArrayList();
         }
        // Setup the XML parser
        XMLReader xr = XMLReaderFactory.createXMLReader();
        xr.setContentHandler(this); // This class contains the event handlers

        Iterator<String> itr = CnetSource.supportedTopics.get(topic).iterator();
        while(itr.hasNext()) {
            // Parse the CNET RSS feeds for each sub topic
            String nextTopic = itr.next();
            xr.parse(new InputSource(url.query(nextTopic)));
        }

        return newsItemList;
    }



    // Event Handles for XML Parser
    @Override
    public void startDocument ()
    {
        // Do nothing
    }

    //Called when the end of the XML file is reached.
    @Override
    public void endDocument ()
    {
        // Do nothing
    }

    //Called when we begin parsing the XML file.
    @Override
    public void startElement (String uri, String name, String qName, Attributes atts)
    {
        this.currentText = ""; // Clear out previous elements characters
        if(qName.equals("item")) {
            // Create a newsItem
            this.parsingItem = true;
            this.currentItem = new NewsItem(this.source);
        }
    }

    //We've reached the end of an XML element.
    @Override
    public void endElement (String uri, String name, String qName) throws SAXException
    {
        if(!this.parsingItem) return; // Continue only if inside an item element

        if(qName.equals("item")) { // Completed NewsItem
            this.newsItemList.add(this.currentItem);
            this.parsingItem = false;
        }
        else
        if(qName.equals("title")) {
            this.currentItem.setTitle(this.currentText);
        }
        else
        if(qName.equals("link")) {
            this.currentItem.setUrl(this.currentText);
        }
        else
        if(qName.equals("pubDate")) {
            try {
                this.currentItem.setTime(this.currentText);
            } catch (ParseException ex) { // Catch any date parsing errors
                throw new SAXException(ex);
            }
        }
    }

    //Parse characters from the current element we're parsing.
    @Override
    public void characters (char ch[], int start, int length)
    {
        for(int i=start;i<start+length;i++){
            this.currentText+=ch[i];
        }
    }
}
